package com.ruoyi.business.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.business.domain.PressureFlowData;
import com.ruoyi.business.mapper.PressureFlowDataMapper;
import com.ruoyi.business.service.IPressureFlowDataService;
import com.ruoyi.business.vo.AirPressureGroupVO;
import com.ruoyi.business.vo.ExperimentTimeRangeVO;
import com.ruoyi.business.vo.PressureFlowPointVO;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import org.springframework.util.CollectionUtils;

/**
 * 压力流量数据Service业务层处理
 * 
 * @author qiancheng
 * @date 2025-09-16
 */
@Service
public class PressureFlowDataServiceImpl extends ServiceImpl<PressureFlowDataMapper, PressureFlowData> implements IPressureFlowDataService
{
    @Autowired
    private PressureFlowDataMapper pressureFlowDataMapper;

    /**
     * 查询压力流量数据
     * 
     * @param id 压力流量数据主键
     * @return 压力流量数据
     */
    @Override
    public PressureFlowData selectPressureFlowDataById(Long id)
    {
        return pressureFlowDataMapper.selectPressureFlowDataById(id);
    }

    /**
     * 查询压力流量数据列表
     * 
     * @param pressureFlowData 压力流量数据
     * @return 压力流量数据
     */
    @Override
    public List<PressureFlowData> selectPressureFlowDataList(PressureFlowData pressureFlowData)
    {
        return pressureFlowDataMapper.selectPressureFlowDataList(pressureFlowData);
    }

    /**
     * 新增压力流量数据
     * 
     * @param pressureFlowData 压力流量数据
     * @return 结果
     */
    @Override
    public int insertPressureFlowData(PressureFlowData pressureFlowData)
    {
        pressureFlowData.setCreateTime(DateUtils.getNowDate());
        return pressureFlowDataMapper.insert(pressureFlowData);
    }

    /**
     * 修改压力流量数据
     * 
     * @param pressureFlowData 压力流量数据
     * @return 结果
     */
    @Override
    public int updatePressureFlowData(PressureFlowData pressureFlowData)
    {
        pressureFlowData.setUpdateTime(DateUtils.getNowDate());
        return pressureFlowDataMapper.updatePressureFlowData(pressureFlowData);
    }

    /**
     * 批量删除压力流量数据
     * 
     * @param ids 需要删除的压力流量数据主键
     * @return 结果
     */
    @Override
    public int deletePressureFlowDataByIds(Long[] ids)
    {
        return pressureFlowDataMapper.deletePressureFlowDataByIds(ids);
    }

    /**
     * 删除压力流量数据信息
     * 
     * @param id 压力流量数据主键
     * @return 结果
     */
    @Override
    public int deletePressureFlowDataById(Long id)
    {
        return pressureFlowDataMapper.deletePressureFlowDataById(id);
    }

    /**
     * 下载压力流量 Excel 模板
     */
    @Override
    public void downloadTemplate(HttpServletResponse response) throws IOException {
        // 1. 读取 resources/template/PV.xlsx 文件
        ClassPathResource resource = new ClassPathResource("template/PV.xlsx");
        if(!resource.exists()) {
            System.out.println("找不到文件");
        } else {
            System.out.println("文件大小：" + resource.contentLength());
        }


        // 2. 设置响应类型和文件名
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename=PV.xlsx");

        // 3. 打开文件输入流和响应输出流
        try (InputStream in = resource.getInputStream();
             ServletOutputStream out = response.getOutputStream()) {

            // 4. 循环读取文件并写入响应
            byte[] buffer = new byte[1024];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }

            // 5. 刷新输出流
            out.flush();
        }
    }

    /**
     * 导入压力流量数据
     *
     * @param file Excel 文件
     * @param importTime 导入时间，由前端传入
     * @return 导入结果信息
     * @throws Exception 解析或保存异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult importPressureFlowData(MultipartFile file, Date importTime,String startTime,String endTime) throws Exception {
        // 1. 校验文件
        if (file.isEmpty()) return AjaxResult.error("文件不能为空");
        String filename = file.getOriginalFilename();
        if (filename == null || (!filename.endsWith(".xlsx") && !filename.endsWith(".xls"))) {
            return AjaxResult.error("请上传Excel文件（.xls或.xlsx）");
        }

        // 2. 初始化Excel
        Workbook workbook = WorkbookFactory.create(file.getInputStream());
        Sheet sheet = workbook.getSheetAt(0);

        // 3. 获取C3-D3合并单元格值（气压）
        final int MERGED_ROW = 2;       // C3-D3对应POI行索引（0开始）
        final int MERGED_COL_START = 2; // C列索引
        final int MERGED_COL_END = 3;   // D列索引
        final int DATA_START_ROW = 4;   // 第5行数据开始（0开始）
        String mergedValue = ExcelUtil.getMergedCellValue(sheet, MERGED_ROW, MERGED_COL_START, MERGED_COL_END);

        // 4. 解析数据行
        List<PressureFlowData> dataList = new ArrayList<>();
        int lastRowNum = sheet.getLastRowNum();
        if (lastRowNum < DATA_START_ROW) {
            workbook.close();
            return AjaxResult.error("Excel中没有有效数据行（至少需要第5行数据）");
        }

        for (int rowNum = DATA_START_ROW; rowNum <= lastRowNum; rowNum++) {
            Row row = sheet.getRow(rowNum);
            if (row == null) continue;

            PressureFlowData data = new PressureFlowData();
            data.setSeq(ExcelUtil.getCellValueAsInteger(row.getCell(0)));            // 序号
            data.setAirPressure(new BigDecimal(mergedValue).setScale(2, RoundingMode.HALF_UP));                          // 气压
            data.setWaterPressure(ExcelUtil.getCellValueAsBigDecimal(row.getCell(1))); // 水压
            data.setWaterFlow(ExcelUtil.getCellValueAsBigDecimal(row.getCell(2)));     // 水流量
            data.setAirFlow(ExcelUtil.getCellValueAsBigDecimal(row.getCell(3)));       // 气流量

            dataList.add(data);
        }
        workbook.close();

        if (dataList.isEmpty()) return AjaxResult.error("未解析到有效数据");

        // 5. 设置公共字段
        Date finalImportTime = importTime != null ? importTime : new Date();
        Date now = new Date();
        dataList.forEach(d -> {
            d.setImportDay(finalImportTime);
            d.setStartTime(startTime);
            d.setEndTime(endTime);
            d.setDelFlag("0");
            d.setCreateTime(now);
            d.setCreateBy("system");
        });

        // 6. 查询已有数据（按导入时间）
        List<PressureFlowData> existingList = pressureFlowDataMapper.selectByImportTime(finalImportTime,
                new BigDecimal(mergedValue));
        Map<String, PressureFlowData> existingMap = existingList.stream()
                .collect(Collectors.toMap(
                        d -> d.getAirPressure() + "-" + d.getSeq(),  // 组合 key：气流量 + 序号
                        d -> d
                ));

        // 7. 分为新增和更新
        List<PressureFlowData> insertList = new ArrayList<>();
        List<PressureFlowData> updateList = new ArrayList<>();
        for (PressureFlowData data : dataList) {
            String key = data.getAirPressure() + "-" + data.getSeq();
            PressureFlowData exist = existingMap.get(key);
            if (exist != null) {
                // 更新
                exist.setAirPressure(data.getAirPressure());
                exist.setWaterPressure(data.getWaterPressure());
                exist.setWaterFlow(data.getWaterFlow());
                exist.setAirFlow(data.getAirFlow());
                exist.setUpdateTime(now);
                exist.setUpdateBy("system");
                updateList.add(exist);
            } else {
                // 新增
                insertList.add(data);
            }
        }

        // 8. 批量插入或更新
        if (!insertList.isEmpty()) this.saveBatch(insertList);
        if (!updateList.isEmpty()) updateList.forEach(this::updateById);

        return AjaxResult.success("导入成功，新增 " + insertList.size() + " 条，更新 " + updateList.size() + " 条，气压：" + mergedValue);
    }


    /**
     * 获取已导入数据的导入时间列表
     */
    @Override
    public List<String> getImportTimeList() {
        List<Date> dateList = pressureFlowDataMapper.selectDistinctImportTime();
        if (CollectionUtils.isEmpty(dateList)) {
            return Collections.emptyList();
        }
        // 格式化为 yyyy-MM-dd HH:mm
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        return dateList.stream()
                .map(d -> LocalDateTime.ofInstant(d.toInstant(), ZoneId.systemDefault()).format(formatter))
                .collect(Collectors.toList());
    }

    /**
     * 获取某个导入日的实验时间范围
     *
     * @param importDay 导入时间
     * @return 实验时间范围列表
     */
    @Override
    public List<ExperimentTimeRangeVO> getPressureFlowTimeRanges(Date importDay) {
        if (importDay == null) {
            return Collections.emptyList();
        }
        return pressureFlowDataMapper.selectTimeRangesByImportDay(importDay);
    }


    /**
     * 获取按气压分组的图表数据（核心接口）
     * @param importDay
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public List<AirPressureGroupVO> getChartDataGroupedByAirPressure(Date importDay, String startTime, String endTime) {
        // 1. 查询所有数据（已按气压和水压排序）
        List<PressureFlowData> allData = pressureFlowDataMapper.selectGroupedByAirPressure(importDay, startTime, endTime);

        // 2. 按气压分组转换为VO，并按气压升序排序
        return allData.stream()
                .collect(Collectors.groupingBy(PressureFlowData::getAirPressure))
                .entrySet().stream()
                .map(entry -> {
                    AirPressureGroupVO groupVO = new AirPressureGroupVO();
                    groupVO.setAirPressure(entry.getKey());

                    List<PressureFlowPointVO> pointVOs = entry.getValue().stream()
                            .map(data -> {
                                PressureFlowPointVO pointVO = new PressureFlowPointVO();
                                pointVO.setWaterPressure(data.getWaterPressure());
                                pointVO.setWaterFlow(data.getWaterFlow());
                                pointVO.setAirFlow(data.getAirFlow());
                                pointVO.setSeq(data.getSeq());
                                return pointVO;
                            })
                            .collect(Collectors.toList());

                    groupVO.setDataPoints(pointVOs);
                    return groupVO;
                })
                // 按 airPressure 升序排序
                .sorted((a, b) -> a.getAirPressure().compareTo(b.getAirPressure()))
                .collect(Collectors.toList());
    }


    /**
     * 获取按气压分组的图表数据（核心接口）
     * 从Service层实现分组逻辑，不依赖XML的resultMap
     * @return 气压分组VO列表
     */
//    @Override
//    public List<AirPressureGroupVO> getChartDataGroupedByAirPressure(Date importTime) {
//        // 1. 查询所有数据（已按气压和水压排序）
//        List<PressureFlowData> allData = pressureFlowDataMapper.selectGroupedByAirPressure(importTime);
//
//        // 2. 在内存中按气压分组，并转换为VO
//        return allData.stream()
//                // 按气压分组
//                .collect(Collectors.groupingBy(PressureFlowData::getAirPressure))
//                .entrySet().stream()
//                .map(entry -> {
//                    AirPressureGroupVO groupVO = new AirPressureGroupVO();
//                    groupVO.setAirPressure(entry.getKey()); // 设置当前分组的气压值
//
//                    // 转换数据点列表：PressureFlowData → PressureFlowPointVO
//                    List<PressureFlowPointVO> pointVOs = entry.getValue().stream()
//                            .map(data -> {
//                                PressureFlowPointVO pointVO = new PressureFlowPointVO();
//                                pointVO.setWaterPressure(data.getWaterPressure());
//                                pointVO.setWaterFlow(data.getWaterFlow());
//                                pointVO.setAirFlow(data.getAirFlow());
//                                pointVO.setSeq(data.getSeq());
//                                return pointVO;
//                            })
//                            .collect(Collectors.toList());
//
//                    groupVO.setDataPoints(pointVOs);
//                    return groupVO;
//                })
//                .collect(Collectors.toList());
//    }

}
